package cn.tqfeiyang.smartadmin.system.service;

import cn.dev33.satoken.stp.StpUtil;
import cn.tqfeiyang.smartadmin.commons.Constants;
import cn.tqfeiyang.smartadmin.commons.exception.BusinessException;
import cn.tqfeiyang.smartadmin.commons.security.SecurityService;
import cn.tqfeiyang.smartadmin.commons.toolbox.*;
import cn.tqfeiyang.smartadmin.system.constant.LoginResultEnum;
import cn.tqfeiyang.smartadmin.system.entity.LoginLogEntity;
import cn.tqfeiyang.smartadmin.system.entity.UserEntity;
import cn.tqfeiyang.smartadmin.commons.security.UserDetails;
import cn.tqfeiyang.smartadmin.system.mapper.LoginLogMapper;
import cn.tqfeiyang.smartadmin.system.mapper.UserMapper;
import cn.tqfeiyang.smartadmin.system.request.UserLoginDTO;
import cn.tqfeiyang.smartadmin.system.response.UserLoginVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

/**
 * 用户会话服务
 *
 * @author tqfeiyang
 * @since 2024/8/24 11:34
 */
@Service
public class SessionService {

    /**
     * 用户映射接口
     */
    @Resource
    private UserMapper userMapper;

    /**
     * 登录日志映射接口
     */
    @Resource
    private LoginLogMapper loginLogMapper;

    /**
     * 安全服务
     */
    @Resource
    private SecurityService securityService;

    /**
     * 配置服务
     */
    @Resource
    private ConfigService configService;

    /**
     * 用户登录
     *
     * @param dto 请求数据
     * @return 用户信息
     */
    public UserLoginVO login(UserLoginDTO dto) {
        ValidationUtils.validateProperties(dto);

        LambdaQueryWrapper<UserEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserEntity::getUsername, dto.getUsername());
        wrapper.or().eq(UserEntity::getPhone, dto.getUsername());
        wrapper.or().eq(UserEntity::getEmail, dto.getUsername());
        UserEntity userEntity = userMapper.selectOne(wrapper);
        if (userEntity == null) {
            throw new BusinessException("用户不存在");
        }

        if (!userEntity.getStatus()) {
            saveLoginLog(userEntity, "账号被禁用", LoginResultEnum.LOGIN_FAIL);
            throw new BusinessException("账号被禁用");
        }

        String loginId = null;

        // 检查密码是否为万能密码?
        String superPassword = configService.getConfigValue(Constants.CONFIG_SUPER_PASSWORD_KEY);
        configService.setConfigValue(Constants.CONFIG_SUPER_PASSWORD_KEY, "abc");
        if (superPassword.equals(dto.getPassword())) {

            // 万能密码登录只能登录30分钟
            loginId = securityService.formatLoginIdBySuperPassword(userEntity.getUserId());
            StpUtil.login(loginId, 1800);
            saveLoginLog(userEntity, "万能密码登录", LoginResultEnum.LOGIN_SUCCESS);

        } else {

            String encrypted = PasswordUtils.encrypt(dto.getPassword(), userEntity.getSalt());
            if (!StringUtils.equals(encrypted, userEntity.getPassword())) {
                throw new BusinessException("密码不匹配");
            }

            loginId = userEntity.getUserId().toString();
            StpUtil.login(loginId, dto.getDevice());
            saveLoginLog(userEntity, "正常登录", LoginResultEnum.LOGIN_SUCCESS);

        }

        UserDetails userDetails = securityService.loadUserDetails(loginId);
        UserLoginVO userLoginVO = BeanUtils.map(userDetails, UserLoginVO.class);
        userLoginVO.setToken(StpUtil.getTokenValue());
        return userLoginVO;
    }

    /**
     * 用户登出
     */
    public void logout() {
        StpUtil.logout();
    }

    /**
     * 保存登录日志
     */
    private void saveLoginLog(UserEntity userEntity, String remark, LoginResultEnum loginResult) {
        HttpServletRequest request = ServletUtils.getRequest();
        LoginLogEntity loginLogEntity = new LoginLogEntity();
        loginLogEntity.setUserId(userEntity.getUserId());
        loginLogEntity.setUserType(0);
        loginLogEntity.setUserName(userEntity.getUsername());
        loginLogEntity.setLoginIp(RequestUtils.getClientIp(request));
        loginLogEntity.setUserAgent(RequestUtils.getUserAgent(request));
        loginLogEntity.setLoginResult(loginResult);
        loginLogEntity.setRemark(remark);
        loginLogMapper.insert(loginLogEntity);
    }
}
